tags ← ctags
cscope.files ← 인덱싱 대상 목록
cscope.out ← cscope 본 DB
cscope.in.out ← -q 역색인
cscope.po.out ← -q 역색인
추가 옵션
의미
-i FILE
인덱싱 대상 파일 목록 지정
-k
시스템 헤더(/usr/include)를 검색에서 제외. 커널·펌웨어처럼 자체 헤더만 쓰는 프로젝트에 적합
3. vim 연동
일회성으로 붙일 때:
:cs add cscope.out:cs show:set tags=./tags;
set tags=./tags; 뒤의 세미콜론은 “현재 파일 위치에서 상위 디렉터리로 올라가며 tags를 찾아라” 는 의미다.
소스 트리 깊은 곳에서 vim을 열어도 루트의 tags를 찾아준다.
권장 ~/.vimrc
" 현재 위치부터 상위로 tags 탐색set tags=./tags,tags;$HOME" Ctrl-] 을 누르면 ctags보다 cscope를 먼저 조회set cscopetagset csto=0" 검색 결과를 quickfix 창으로set cscopequickfix=s-,c-,d-,i-,t-,e-" 프로젝트 루트에 cscope.out 이 있으면 자동 로드if filereadable("cscope.out") silent! cs add cscope.outendif" Ctrl+\ 뒤에 알파벳 → 커서 아래 단어로 검색nnoremap <C-\>g :cs find g <C-R><C-W><CR>nnoremap <C-\>c :cs find c <C-R><C-W><CR>nnoremap <C-\>d :cs find d <C-R><C-W><CR>nnoremap <C-\>s :cs find s <C-R><C-W><CR>
설정
효과
cscopetag
Ctrl-] · :tag 가 cscope도 함께 조회
csto=0
조회 우선순위 — 0은 cscope 먼저, 1은 ctags 먼저
cscopequickfix
결과가 여러 개일 때 quickfix 목록으로. :copen / :cnext / :cprevious / :cclose 로 순회
4. ctags 조작 (정의로 점프)
동작
명령
정의로 이동
Ctrl-]
이동 전 위치로 복귀 (태그 스택 pop)
Ctrl-t
일반 점프 위치로 복귀
Ctrl-o
정의 후보 목록 표시
g]
이름으로 정의 이동
:tag 함수이름
이름의 정의 후보 목록
:tselect 함수이름 (:ts)
다음 / 이전 후보
:tnext / :tprevious
같은 이름이 여러 개일 때
레거시 C 코드는 init(), process() 같은 이름이 모듈마다 존재하는 경우가 많다.
Ctrl-] 로 엉뚱한 곳에 도착하면 Ctrl-t 로 돌아와 :ts 함수명 으로 목록을 보고 고르는 게 빠르다.
5. cscope 검색 명령
:cs find <종류> <검색어>
명령
의미
언제 쓰나
:cs find s name
심볼이 사용된 모든 위치
이 변수를 건드리면 어디가 영향받나
:cs find g name
전역 정의 찾기
정의가 어디지
:cs find d name
name이 호출하는 함수
이 함수가 내부에서 뭘 부르나 (순방향)
:cs find c name
name을 호출하는 함수
누가 이걸 부르나 (역방향) ⭐ 가장 많이 씀
:cs find t text
문자열 검색
로그 메시지로 코드 위치 찾기
:cs find e regex
정규식 검색
:cs find f file.c
파일 찾기
:cs find i header.h
이 헤더를 include하는 파일
헤더 수정 시 영향 범위 파악
커서 아래 단어를 명령줄에 삽입하려면 Ctrl-rCtrl-w:
:cs find g <Ctrl-r><Ctrl-w>
6. 호출 관계 추적
process_request()를 누가 호출하는지 (역방향, 위로):
:cs find c process_request
process_request()가 무엇을 호출하는지 (순방향, 아래로):
:cs find d process_request
결과에서 상위 함수를 열고 다시 :cs find c 상위함수 를 반복하면 호출 경로를 위로 계속 거슬러 올라갈 수 있다.
??? ← :cs find c main_loop (계속 위로)
│
main_loop()
│ ← :cs find c process_request
▼
process_request()
│ ← :cs find d process_request
▼
parse_header() send_reply()
cscope는 정적 호출 관계다
cscope가 보여주는 것은 소스 코드상 그렇게 부를 수 있다는 관계일 뿐, 실제 실행 중의 호출 스택이 아니다.
함수 포인터로 호출되는 경로(콜백 핸들러 등)는 잡히지 않는다.
실제 런타임 스택은 GDB로 확인한다 — GDB 실전 디버깅 참고.
7. DB 갱신
소스가 바뀌거나 파일이 추가되면 인덱스는 자동으로 갱신되지 않는다. 점프가 엉뚱한 줄로 가면 대부분 DB가 낡은 것이다.
ccomplete#Complete가 구조체 멤버를 알아내려면 ctags가 --fields=+iaS 옵션으로 멤버 정보까지 인덱싱해야 한다.
ctags -R --fields=+iaS --extra=+q .
이 옵션 없이 만든 tags는 함수/변수 정의 점프는 되지만 멤버 자동완성은 부실하다.
IDE 자동완성과의 차이
LSP 기반(clangd 등) 자동완성은 실시간 타입 추론이지만, 위 방식은 tags 파일 스냅샷 기준이다.
코드를 크게 고친 뒤에는 7번의 mktags(또는 8번의 :make)로 갱신해야 최신 심볼이 완성 후보에 뜬다.
10. 함수 시그니처(파라미터 순서) 확인 — IDE 파라미터 힌트 대체
IDE는 함수를 호출하는 도중 “몇 번째 인자에 뭘 받는지” 툴팁(파라미터 힌트/시그니처 헬프)을 실시간으로 띄워주지만, 이건 LSP(언어 서버)가 타입을 그때그때 분석해야 가능한 기능이라 LSP 플러그인 없는 순정 vim에는 동급 기능이 없다. 대신 아래 두 가지로 대체한다.
10-1. 표준 라이브러리 함수는 K (man 페이지)
vim은 C 파일을 열면 keywordprg가 기본적으로 man을 가리킨다. 커서를 함수 이름 위에 놓고 K를 누르면 그 함수의 man 페이지가 뜬다.
:set keywordprg=:Man " (선택) :Man 커맨드로 열기 — 분할창으로 보고 싶을 때
strncpy, pthread_create, snprintf, sscanf처럼 표준 C 라이브러리 함수는 K 한 번으로 정확한 파라미터 순서·타입·반환값을 바로 확인할 수 있다. 예: 커서를 strncpy 위에 놓고 K → man 3 strncpy가 열리며 char *strncpy(char *dest, const char *src, size_t n); 시그니처가 그대로 나온다.
select, epoll_wait 같은 시스템 콜도 동일하게 동작한다.
man 섹션 번호
man printf는 셸 명령어(섹션 1)가 먼저 뜰 수 있다. 라이브러리 함수 원형이 필요하면 :Man 3 printf처럼 섹션 3을 명시한다.
10-2. 사용자 정의 함수는 ctags 프리뷰 창
프로젝트 안에서 직접 짠 함수는 man 페이지가 없다. 대신 2번에서 만든 tags를 이용해 커서 위치를 옮기지 않고 정의부(시그니처)만 미리보기 창으로 띄운다.
Ctrl-w } " 커서 아래 함수의 정의를 프리뷰 창(상단 분할)으로 열기Ctrl-w z " 프리뷰 창 닫기:ptag 함수이름 " 이름으로 직접 프리뷰
프리뷰 창은 실제로 커서를 이동시키지 않으므로, 지금 작성 중인 호출 코드를 보면서 위쪽 작은 창에서 파라미터 순서만 확인하고 바로 닫을 수 있다 — IDE의 시그니처 힌트와 체감상 가장 가깝다.
완전한 파라미터 힌트가 필요하면
이것도 “정의부로 잠깐 갔다 오는” 방식이지, 타이핑 중 실시간으로 몇 번째 인자인지 하이라이트해주는 건 아니다. 진짜 IDE 수준 파라미터 힌트가 필요하면 9번에서 언급한 LSP 플러그인(coc.nvim 등, clangd 기반)이 필요하다 — 순정 vim 기능만으로는 여기가 한계.
11. 요즘 LSP와는 어떤 차이가 있나
ctags → 문자/심볼 기반 정의 검색cscope → 소스 코드 참조 관계 검색clangd → 컴파일 정보까지 이해한 semantic 분석 (Go to Definition / Find References / Rename / Hover / Diagnostics / Completion)
ctags/cscope는 여전히 장점이 있다.
설정이 단순하고 DB가 가벼움
터미널 환경에서 잘 동작, 빌드 환경이 불완전해도 사용 가능
오래된/거대한 C 프로젝트, 임베디드/커널 소스 탐색에 유용
특히 **“컴파일은 당장 안 되지만 코드부터 읽어야 하는 상황”**에서는 ctags/cscope가 상당히 편하다.